package com.snowy.framework.wechatAuth.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.snowy.framework.exception.UABPException;
import com.snowy.framework.util.OkHttpUtils;
import com.snowy.framework.wechatAuth.dto.req.WechatAuthReq;
import com.snowy.framework.wechatAuth.dto.req.WechatSignatureReq;
import com.snowy.framework.wechatAuth.dto.resp.SignatureResp;
import com.snowy.framework.wechatAuth.dto.resp.WechatUserInfo;
import com.snowy.framework.wechatAuth.enums.WechatErroEnum;
import com.snowy.framework.wechatAuth.service.WechatAuthService;
import com.snowy.framework.wechatAuth.util.SHA1Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

/**
 * 微信认证服务实现
 *
 * @author hjl
 */
@Slf4j
@Service("wechatAuthService")
public class WechatAuthServiceImpl implements WechatAuthService {
    /**
     * 微信登录取access_token  URL
     */
    private static String WECHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

    /**
     * 微信登录取用户信息 URL
     */
    private static String WECHAT_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";

    /**
     * JSAccess_token URL
     */
    private static String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    private static String JS_SDK_SIGNATURE_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
    /**
     * 获取登录用户手机号
     */
    private static String WECHAT_USERPHOME_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";

    /**
     * 根据授权码取微信用户信息
     *
     * @param wechatAuthReq
     * @return
     */
    @Override
    public WechatUserInfo getWechatUserInfo(WechatAuthReq wechatAuthReq) {
        String appId = wechatAuthReq.getAppId();
        String appSecret = wechatAuthReq.getAppSecret();
        if (StrUtil.hasBlank(appId, appSecret)) {
            throw new UABPException(WechatErroEnum.NO_APPINFO_ERROR);
        }
        // 获取微信认证信息accessToken、openId
        JSONObject jsonObject = this.getAuthInfo(wechatAuthReq.getCode(), appId, appSecret);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        // 判断是否获取到认证信息
        if (StrUtil.hasBlank(accessToken, openId)) {
            throw new UABPException(WechatErroEnum.NO_WECHAT_ASSTOKEN);
        }
        // 取微信用户信息
        WechatUserInfo wechatUserInfo = this.getUserInfo(accessToken, openId);
        return wechatUserInfo;
    }

    @Override
    public SignatureResp getWechatSDKSignature(WechatSignatureReq wechatSignatureReq) {
        String accessToken = this.getAccessToken(wechatSignatureReq.getAppId(), wechatSignatureReq.getAppSecret());
        // 获取JSapiTicket
        String ticket = this.getJSApiTicket(accessToken);
        //生成签名
        SignatureResp resp = this.generateSignature(ticket, wechatSignatureReq.getUrl());
        return resp;
    }

    @Override
    public String getPhoneByAuthCode(String accessToken, String code) {
        code = "{\"code\":\"" + code + "\"}";
        String phoneUrl = String.format(WECHAT_USERPHOME_URL, accessToken);
        String phoneStr;
        try {
            phoneStr = OkHttpUtils.httpPost(phoneUrl, code);
        } catch (Exception e) {
            log.error("==phoneStr==" + e.getMessage());
            throw new UABPException(WechatErroEnum.INTF_ERROR);
        }
        JSONObject respPhoneObj = JSONObject.parseObject(phoneStr);
        JSONObject phoneObj = (JSONObject) respPhoneObj.get("phone_info");
        if (phoneObj == null) {
            throw new UABPException(WechatErroEnum.NO_WECHAT_PHOMEINFO.getReturnCode(), WechatErroEnum.NO_WECHAT_PHOMEINFO.getReturnMsg());
        }
        //获取手机号
        return phoneObj.getString("phoneNumber");

    }

    /**
     * 取微信认证信息
     *
     * @param code
     * @param appId
     * @param appKey
     * @return
     */
    private JSONObject getAuthInfo(String code, String appId, String appKey) {
        // http调用接口获取微信认证信息
        String accessTokenUrl = String.format(WECHAT_ACCESS_TOKEN_URL, appId, appKey, code);
        String authStr = null;
        try {
            authStr = OkHttpUtils.httpGet(accessTokenUrl);
        } catch (Exception e) {
            log.error("==getAuthInfo1==" + e.getMessage());
            throw new UABPException(WechatErroEnum.INTF_ERROR);
        }
        if (StringUtils.isEmpty(authStr)) {
            throw new UABPException(WechatErroEnum.INTF_ERROR);
        }
        // 返回字符串转换为JSONObject
        JSONObject authJsonObject;
        try {
            authJsonObject = JSONObject.parseObject(authStr);
        } catch (Exception e) {
            log.error("==getAuthInfo2==" + e.getMessage());
            throw new UABPException(WechatErroEnum.JSON_ANALYSIS_ERROR);
        }
        // 解析authJsonObject获取token
        if (!authJsonObject.containsKey("access_token")) {
            throw new UABPException(WechatErroEnum.NO_WECHAT_ASSTOKEN);
        }
        // 取openId
        if (!authJsonObject.containsKey("openid")) {
            throw new UABPException(WechatErroEnum.NO_WECHAT_OPEN_ID);
        }
        return authJsonObject;
    }

    /**
     * 取微信用户信息
     *
     * @return
     */
    private WechatUserInfo getUserInfo(String accessToken, String openId) {
        //1、http调用微信接口获取用户信息
        String userUrl = String.format(WECHAT_USERINFO_URL, accessToken, openId);
        String userStr = null;
        try {
            userStr = OkHttpUtils.httpGet(userUrl);
        } catch (Exception e) {
            log.error("==getUserInfo1==" + e.getMessage());
        }
        // 判断用户信息是否未取到
        if (StrUtil.isEmpty(userStr)) {
            throw new UABPException(WechatErroEnum.INTF_ERROR);
        }
        // 解析用户信息
        JSONObject userJsonObject = null;
        try {
            userJsonObject = JSONObject.parseObject(userStr);
        } catch (Exception e) {
            log.error("==getUserInfo2==" + e.getMessage());
            throw new UABPException(WechatErroEnum.JSON_ANALYSIS_ERROR);
        }
        // 判断是否取到用户昵称
        if (!userJsonObject.containsKey("nickname")) {
            throw new UABPException(WechatErroEnum.NO_WECHAT_USERINFO);
        }
        //3、设置用户信息
        WechatUserInfo wechatUserInfo = JSONObject.parseObject(userStr, WechatUserInfo.class);
        wechatUserInfo.setOpenId(userJsonObject.getString("openid"));
        wechatUserInfo.setNickName(userJsonObject.getString("nickname"));
        wechatUserInfo.setHeadImageUrl(userJsonObject.getString("headimgurl"));
        wechatUserInfo.setUnionId(userJsonObject.getString("unionid"));
        wechatUserInfo.setSex(userJsonObject.getInteger("sex"));

        return wechatUserInfo;
    }

    /**
     * 获取微信accessToken
     *
     * @return
     */
    private String getAccessToken(String appId, String appSecret) {
        // 获取accessToken
        String accessTokenUrl = String.format(GET_ACCESS_TOKEN_URL, appId, appSecret);
        String response = null;
        try {
            response = OkHttpUtils.httpGet(accessTokenUrl);
        } catch (Exception e) {
            throw new UABPException(e);
        }
        JSONObject jsonResp = JSONObject.parseObject(response);
        log.info("获取accessToken返回" + jsonResp.toString());
        // 获取用户access_token
        String access_token = jsonResp.getString("access_token");

        //判断是否取到access_token
        if (StrUtil.isBlank(access_token)) {
            throw new UABPException(jsonResp.getString("errcode"), jsonResp.getString("errmsg"));
        }
        return access_token;
    }

    private String getJSApiTicket(String accessToken) {
        // 获取accessToken
        String signatureUrl = String.format(JS_SDK_SIGNATURE_URL, accessToken);
        String response = null;
        try {
            response = OkHttpUtils.httpGet(signatureUrl);
        } catch (Exception e) {
            throw new UABPException(e);
        }
        JSONObject jsonResp = JSONObject.parseObject(response);
        log.info("获取ticket返回" + jsonResp.toString());
        // 获取JSapiTicket
        String ticket = jsonResp.getString("ticket");

        //判断是否取到ticket
        if (StrUtil.isBlank(ticket)) {
            throw new UABPException(jsonResp.getString("errcode"), jsonResp.getString("errmsg"));
        }
        return ticket;
    }

    /**
     * 参数签名
     *
     * @param ticket
     * @param shareUrl
     * @return
     */
    private SignatureResp generateSignature(String ticket, String shareUrl) {
        String reqTime = String.valueOf(DateUtil.currentSeconds());
        String nonceStr = RandomUtil.randomString(10);
        String url = shareUrl;
        String signature = SHA1Util.encode("jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + reqTime + "&url=" + url);
        log.info("请求签名参数" + "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + reqTime + "&url=" + url);
        log.info("签名" + signature);
        SignatureResp resp = new SignatureResp();
        resp.setNonceStr(nonceStr);
        resp.setTimestamp(reqTime + "");
        resp.setSignature(signature);
        resp.setTicket(ticket);
        return resp;
    }
}
